/*
Démonstration de libhd44780fw
Auteur : Philippe Proulx (eeppeliteloop@gmail.com)
*/

#ifndef F_CPU
#define F_CPU 8000000UL
#endif

#include <avr/io.h>
#include <util/delay.h>

/* À inclure absolutement : */
#include "hd44780_low.h"
#include "hd44780fw.h"

/* À inclure pour faciliter la configuration en INF1995 : */
#include "inf1995_init_hd44780.h"

/* Inclus ici seulement pour les applications : */

#define DEMO_DDR	DDRC	/* DDR utilisé pour l'afficheur */
#define DEMO_PORT	PORTC	/* Port utilisé pour l'afficheur */

/* Attente entre les étapes de la démonstration : */
static void w(void) {
	_delay_ms(2000.0);
}

/* Applications potentielles : */
static void banner(struct hd44780fw_conf* fw_conf, char* text,
	uint16_t interval);
static void wave(struct hd44780fw_conf* fw_conf, uint16_t rep,
	uint16_t ms_interval);

/* Démonstration : */
int main(void) {	
	/* Instances de configurations bas-niveau et haut-niveau : */
	struct hd44780_l_conf low_conf;
	struct hd44780fw_conf fw_conf;
	struct hd44780fw_conf* fwc = &fw_conf;	/* Raccourci */
	
	/* Initialisation automatique des configurations pour INF1995 : */
	inf1995_init_hd44780(&DEMO_DDR, &DEMO_PORT, &fw_conf, &low_conf);
	
	/* Initialisation de l'afficheur LCD : */
	hd44780fw_init(fwc);
	
	/* Écriture d'un simple caractère en début de première ligne : */
	hd44780fw_put(fwc, 'i');
	w();

	/* Ajout d'autres caractères : */
	hd44780fw_put(fwc, 'n');
	hd44780fw_put(fwc, 'f');
	hd44780fw_put(fwc, '1');
	hd44780fw_put(fwc, '9');
	hd44780fw_put(fwc, '9');
	hd44780fw_put(fwc, '5');
	w();
	
	/* Nettoyage de l'affichage : */
	hd44780fw_clear(fwc);
	w();
	
	/* Affichage d'une chaine sur la première ligne, à la case 2 : */
	hd44780fw_write(fwc, "premiere !", 2, HD44780FW_WR_NO_CLEAR_BEFORE);
	w();
	
	/* Ajout d'une sous-chaîne à la suite : */
	hd44780fw_cat_string(fwc, "woooowww !!");
	w();
	
	/* Suppression des 9 caractères précédents : */
	hd44780fw_rem(fwc, 9);
	w();
	
	/* Remplacement du contenu actuel par une nouvelle chaine : */
	hd44780fw_write(fwc, "nouveau truc ", 0, HD44780FW_WR_CLEAR_BEFORE);
	w();
	
	/* Ajout de trois nombres avec des espaces entre chaque : */
	hd44780fw_cat_uint8(fwc, 215);
	hd44780fw_cat_char(fwc, ' ');
	hd44780fw_cat_int8(fwc, -179);
	hd44780fw_cat_char(fwc, ' ');
	hd44780fw_cat_uint16(fwc, 6);
	w();
	
	/* Affichage d'une chaîne, à la case 5 de la deuxième ligne : */
	hd44780fw_write(fwc, "\x7e yeah! \x7f", 16 + 5,
		HD44780FW_WR_NO_CLEAR_BEFORE);
	w();
	
	/* Fixage de l'index de curseur/clignotement à la case 9 et activation
	du clignotement : */
	hd44780fw_set_bc_index(fwc, 9);
	hd44780fw_en_blink(fwc, HD44780FW_BLINK_ON);
	w();
	
	/* Activation du curseur (le matériel limite son index au même que celui
	du clignotement) : */
	hd44780fw_en_cur(fwc, HD44780FW_CURSOR_ON);
	w();
	
	/* Désactivation du clignotement : */
	hd44780fw_en_blink(fwc, HD44780FW_BLINK_OFF);
	w();
	
	/* Parcours de la case 0 à la dernière case avec le curseur : */
	int8_t i;
	for (i = 0; i < 32; ++i) {
		hd44780fw_set_bc_index(fwc, i);
		_delay_ms(100.0);
	}
	w();
	
	/* Parcours de la dernière case à la case 0 avec le clignotement : */
	hd44780fw_en_cursor(fwc, HD44780FW_CURSOR_OFF);
	hd44780fw_en_blink(fwc, HD44780FW_BLINK_ON);
	for (i = 31; i >= 0; --i) {
		hd44780fw_set_bc_index(fwc, i);
		_delay_ms(100.0);
	}
	w();
	
	/* Désactivation du clignotement : */
	hd44780fw_en_blink(HD44780FW_BLINK_OFF);
	
	/* Application : bannière de texte sur la première ligne : */
	banner(fwc, (char*) "bonjour le monde. voici une banniere de texte !",
		100);
	w();
	
	/* Création d'un caractère personnalisé à l'index 3 (les bits à 1 sont
	des pixels actifs et à 0 des pixels inactifs) : */
	uint8_t cc [] = {
		0x04, /*   #    */
		0x0a, /*  # #   */
		0x1f, /* #####  */
		0x04, /*   #    */
		0x04, /*   #    */
		0x04, /*   #    */
		0x04, /*   #    */
		0x03  /*    ##  */
	};
	hd44780fw_build_cc(fwc, 3, cc);
	
	/* Affichage du dernier caractère personnalisé à la case 7 en effaçant
	le contenu actuel : */
	hd44780fw_write(fwc, "\x03", 7, HD44780FW_WR_CLEAR_BEFORE);
	w();
	
	/* Création d'un autre caractère personnalisé à l'index 7, mais de
	façon programmatique, et remplissage de la deuxième ligne : */
	for (i = 0; i < 8; ++i) {
		cc[i] = _BV(i) >> (i > 4 ? 5 : 0);
	}
	hd44780fw_build_cc(fwc, 7, cc);
	for (i = 16; i < 32; ++i) {
		hd44780fw_write(fwc, "\x07", i);
	}
	w();
	
	/* Application : grosse vague rapide, 10 fois : */
	wave(fwc, 10, 10);
	w();
	
	/* Grosse vague, moins rapide, 5 fois : */
	wave(fwc, 5, 40);
	w();
	
	/* Affichage de tous les caractères possibles une fois par case (noter
	la rapidité d'exécution) : */
	hd44780fw_clear(fwc);
	char c;
	for (uint8_t i = 0; i < 32; ++i) {
		for (c = 0x21; c <= 0xdf; ++c) {
			hd44780fw_cat_char(fwc, c);
			hd44780fw_rem(fwc, 1);
		}
		hd44780fw_cat_char(fwc, 0xff);
	}
	w();
	
	/* Fin de la démonstration (avec définition d'un 'é' à l'index 4) : */
	uint8_t cc2 [] = {
		0x02, /*    #   */
		0x04, /*   #    */
		0x0e, /*  ###   */
		0x11, /* #   #  */
		0x1f, /* #####  */
		0x10, /* #      */
		0x0e, /*  ###   */
		0x00  /*        */
	};
	hd44780fw_build_cc(fwc, 4, cc2);
	char end [] = "Fin de la d\x04mo !";
	hd44780fw_write(fwc, end, 0, HD44780FW_WR_CLEAR_BEFORE);
	hd44780fw_cat_string(fwc, end);
	
	/* Boucle infinie : */
	for (;;);
	
	return 0;
}

/**
 * Application - bannière de texte.
 *
 * @param fw_conf	Configuration du framework HD44780
 * @param text		Texte à afficher (avec jeu de caractères de l'afficheur)
 * @param ms_interval	Intervalle en millisecondes entre chaque décallage
 */
static void banner(struct hd44780fw_conf* fw_conf, char* text,
uint16_t interval);
	uint8_t start = 0, stop = 1, index = 0;
	uint16_t msg_len = cp_strlen(text);
	char t_char = 0;
	
	hd44780fw_clear(fw_conf);
	cp_wait_ms(ms_interval);
	
	while (stop <= msg_len && start < msg_len - 1) {
		if (stop <= LCM_FW_HALF_CH) {
			index = LCM_FW_HALF_CH - stop;
		} else {
           	++start;
			index = 0;
		}
		
		t_char = text[stop];
		text[stop] = 0;
		hd44780fw_write(fw_conf, text + start, index,
			(stop == msg_len) ? HD44780FW_WR_CLEAR_BEFORE :
			HD44780FW_WR_NO_CLEAR_BEFORE);
		text[stop] = t_char;

		if (stop != msg_len) {
			++stop;
		}

		cp_wait_ms(ms_interval);
	}
	
	hd44780fw_clear(fw_conf);
	cp_wait_ms(ms_interval);
}

/**
 * Application - vague.
 *
 * @param fw_conf	Configuration du framework HD44780
 * @param rep		Nombre de répétitions
 * @param ms_interval	Intervalle en millisecondes entre chaque mouvement
 */
static void wave(struct hd44780fw_conf* fw_conf, uint16_t rep,
uint16_t ms_interval) {
	uint8_t t_per [8];
	uint8_t i, j;
	uint16_t k;
	
	for (i = 0; i < 8; ++i) {
		for (uint8_t j = 0; j < 8; ++j) {
			if (j == i) {
				t_per[j] = 0xff;
			} else {
				t_per[j] = 0;
			}
		}
		hd44780fw_build_cc(fw_conf, i, t_per);
	}
	
	char custom_l1 [] = "\x20\x07\x05\x04\x03\x02\x02\x01\x01\x01\x02\x02"
		"\x03\x04\x05\x07\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
		"\x20\x20\x20\x20\x20\x20\x07\x05\x04\x03\x02\x02\x01\x01\x01"
		"\x02\x02\x03\x04\x05\x07";
	char custom_l2 [] = "\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
		"\x20\x20\x20\x20\x20\x08\x02\x03\x04\x05\x05\x06\x06\x06\x05"
		"\x05\x04\x03\x02\x08\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
		"\x20\x20\x20\x20\x20\x20";

	char t_char;
	
	hd44780fw_clear(fw_conf);
	
	for (k = 0; k < rep; ++k) {
		for (i = 0; i < 32; ++i) {
			t_char = custom_l1[i + 16];
			custom_l1[i + 16] = '\0';
			
			hd44780fw_write(fw_conf, custom_l1 + i, 0,
				HD44780FW_WR_NO_CLEAR_BEFORE);
			
			custom_l1[i + 16] = t_char;
			t_char = custom_l2[i + 16];
			custom_l2[i + 16] = 0;
			
			hd44780fw_write(fw_conf, custom_l2 + i, 16,
				HD44780FW_WR_NO_CLEAR_BEFORE);

			custom_l2[i + 16] = t_char;
			
			cp_wait_ms(ms_interval);
		}
	}
	
	hd44780fw_clear(fw_conf);
}
